/*
 * util.cpp
 *
 *  Created on: Aug 12, 2014
 *      Author: burek
 */

#include "util.h"
#include "common.h"

#include <cstdlib>
#include <ctime>
#include <cstdio>

#define RSEEDS (256)
#define RRAND_MAX (32767)

int rnums[RSEEDS] =
{7755,22514,9910,24474,3072,12157,21533,8522,32236,18756,18420,6831,31455,
 24842,32614,1979,4243,6781,10748,4612,13595,1120,23695,9089,32580,12882,22813,
 26086,20372,13895,18184,15289,7162,12315,11141,6746,14569,14853,21190,31784,
 16430,4732,5538,8107,156,27323,25233,22391,2969,28205,29613,18972,9380,29167,
 7228,22352,8230,7722,22869,12416,48,7468,11874,11579,24744,27273,5412,9286,
 31963,29820,23949,20166,7361,21730,22776,12692,2060,23895,858,14065,13124,15107,
 11075,28269,32389,11583,29445,29960,8455,18105,16629,20880,31042,4669,14927,9410,
 24359,22011,9511,16781,32455,6741,20243,10796,3643,31107,32582,8108,27574,25481,
 6867,15495,5721,18225,19515,30781,13651,24466,27637,15418,4124,12623,4887,24700,
 1935,19646,23571,24570,9597,1482,7251,17247,13985,27558,6600,28510,8492,23147,
 7286,16618,27710,19512,23288,1858,24156,11753,3867,11711,6135,4033,30124,14131,
 24540,11724,19777,240,12936,7486,19268,28968,13393,281,10315,3818,19861,20142,
 3505,7151,30163,20475,10161,8354,3860,57,28143,1136,4459,10570,18702,8356,19196,
 7454,14677,13862,32026,18239,28124,23223,26744,5985,9213,6089,16336,29148,
 18766,13748,17937,26852,10456,28766,1010,8032,27683,26645,14590,10894,10210,
 19875,28219,31830,15855,20455,30282,25665,24920,20656,14637,14604,26123,10772,
 6079,23683,19439,21249,2794,26041,13732,21379,2279,27667,29619,20813,13916,
 22918,27616,3918,20422,16092,1897,14842,728,3555,9091,4451,30095,23868,23181,
 12958,30036,23832,10093,2432,1224,29102,13618,10097};

int __rpos = 0;

inline int rrand()
{
	__rpos = __rpos % RSEEDS;
	rnums[(__rpos + RSEEDS - 1) % RSEEDS] ^= rnums[__rpos];
	return rnums[__rpos++];
}

void R4_rerandomize()
{
	srand(time(0));
	for(int i = 0; i < RSEEDS; ++i)
		rnums[i] ^= (rand() % RRAND_MAX);
}

bool R4_chance(int percent)
{
	return (rrand() % 10000 < percent * 100);
}

int R4_randRangeI(int min, int max)
{
	return rrand() % (max - min + 1) + min;
}

float R4_randRangeF(float min, float max)
{
	return ((float)rrand() / (float)RRAND_MAX) * (max - min) + min;
}

float R4_randRangeFS(float min, float max)
{
	if(R4_chance(50))
		return (((float)rrand() / (float)RRAND_MAX) * (max - min) + min);
	else
		return -(((float)rrand() / (float)RRAND_MAX) * (max - min) + min);
}

uint32_t R4_calcSimpleHash(const char * txt)
{
	uint32_t hash = 0;
	const uint8_t * utxt = (uint8_t*)txt;

	while((*utxt) != '\0')
	{
		//hash = ((hash << 3) ^ (*utxt)) + ((hash >> 29) & 7);
		hash = (hash << 1) + (*utxt);
		utxt++;
	}

	return hash;
}

void R4_endianSwap(uint16_t & x)
{
	uint8_t * array = (uint8_t*)(&x);
	R4_swap(array[0], array[1]);
}

void R4_endianSwap(uint32_t & x)
{
	uint8_t * array = (uint8_t*)(&x);
	R4_swap(array[0], array[3]);
	R4_swap(array[1], array[2]);
}

void R4_endianSwap(uint64_t & x)
{
	uint8_t * array = (uint8_t*)(&x);
	R4_swap(array[0], array[7]);
	R4_swap(array[1], array[6]);
	R4_swap(array[2], array[5]);
	R4_swap(array[3], array[4]);
}

void R4_endianSwap(int16_t & x)
{
	uint8_t * array = (uint8_t*)(&x);
	R4_swap(array[0], array[1]);
}

void R4_endianSwap(int32_t & x)
{
	uint8_t * array = (uint8_t*)(&x);
	R4_swap(array[0], array[3]);
	R4_swap(array[1], array[2]);
}

void R4_endianSwap(int64_t & x)
{
	uint8_t * array = (uint8_t*)(&x);
	R4_swap(array[0], array[7]);
	R4_swap(array[1], array[6]);
	R4_swap(array[2], array[5]);
	R4_swap(array[3], array[4]);
}

uint16_t R4_endianSwapR(uint16_t x)
{
	return x<<8 | x>>8;
}

uint32_t R4_endianSwapR(uint32_t x)
{
	return x>>24 | (x>>8&0xff00) | (x<<8&0xff0000) | x<<24;
}

uint64_t R4_endianSwapR(uint64_t x)
{
	return R4_endianSwapR(((uint32_t)x)+0ULL)<<32 | R4_endianSwapR((uint32_t)(x>>32));
}

int16_t R4_endianSwapR(int16_t x)
{
	return x<<8 | x>>8;
}

int32_t R4_endianSwapR(int32_t x)
{
	return x>>24 | (x>>8&0xff00) | (x<<8&0xff0000) | x<<24;
}

int64_t R4_endianSwapR(int64_t x)
{
	return R4_endianSwapR(((int32_t)x)+0ULL)<<32 | R4_endianSwapR((int32_t)(x>>32));
}

bool isPOT(uint32_t n)
{
	return (n & (n - 1)) == 0;
}

uint32_t nextPOT(uint32_t n)
{
	--n;
	for(int i = 1; i < 32; i <<= 1)
		n = n | n >> i;
	return n + 1;
}

glm::vec3 R4_colorFromRGB(int r, int g, int b)
{
	return glm::vec3(r / 255.0f, g / 255.0f, b / 255.0f);
}

glm::vec4 R4_colorFromRGBA(int r, int g, int b, int a)
{
	return glm::vec4(r / 255.0f, g / 255.0f, b / 255.0f, a / 255.0f);
}

glm::vec3 R4_colorFromRGB(uint32_t rgb)
{
	uint8_t r = (rgb >> 16) & 0xFF;
	uint8_t g = (rgb >> 8) & 0xFF;
	uint8_t b = (rgb) & 0xFF;
	return glm::vec3(r / 255.0f, g / 255.0f, b / 255.0f);
}

glm::vec4 R4_colorFromRGBA(uint32_t rgba)
{
	uint8_t a = (rgba >> 24) & 0xFF;
	uint8_t r = (rgba >> 16) & 0xFF;
	uint8_t g = (rgba >> 8) & 0xFF;
	uint8_t b = (rgba) & 0xFF;
	return glm::vec4(r / 255.0f, g / 255.0f, b / 255.0f, a / 255.0f);
}

glm::vec3 R4_colorFromHexRGB(const char * hex)
{
	if(hex == NULL) return glm::vec3();
	uint32_t rgb = 0;
	if(sscanf(hex, "%x", &rgb))
		return R4_colorFromRGB(rgb);
	else
		return glm::vec3();
}

glm::vec4 R4_colorFromHexRGBA(const char * hex)
{
	if(hex == NULL) return glm::vec4();
	uint32_t rgba = 0;
	if(sscanf(hex, "%x", &rgba))
		return R4_colorFromRGBA(rgba);
	else
		return glm::vec4();
}

uint32_t R4_rgbFromVec(const glm::vec3 & v)
{
	return (((uint8_t)(v.r * 255.0f)) << 16) |
			(((uint8_t)(v.g * 255.0f)) << 8) |
			(((uint8_t)(v.b * 255.0f)));
}

uint32_t R4_rgbaFromVec(const glm::vec4 & v)
{
	return (((uint8_t)(v.a * 255.0f)) << 24) |
			(((uint8_t)(v.r * 255.0f)) << 16) |
			(((uint8_t)(v.g * 255.0f)) << 8) |
			(((uint8_t)(v.b * 255.0f)));
}
